/*
 *  cpu.h
 *
 *  Created on: 2010-5-5
 *      Author: liuyond
 */

#ifndef CPU_H
#define CPU_H

#include "common.h"

#define HAS_IMM   0x000F
#define IMM_BYTE  0x0001
#define IMM_WORD  0x0002
#define IMM_DWORD 0x0003
#define GRP_BYTE  0x0004
#define GRP_WORD  0x0005
#define HAS_MODRM 0x0100

#define ADD_BYTE  0x0001
#define ADD_WORD  0x0002
#define ADC_BYTE  0x0003
#define ADC_WORD  0x0004
#define SBB_BYTE  0x0005
#define SBB_WORD  0x0006
#define SUB_BYTE  0x0007
#define SUB_WORD  0x0008
#define CMP_BYTE  0x0009
#define CMP_WORD  0x000A
#define INC_BYTE  0x000B
#define INC_WORD  0x000C
#define DEC_BYTE  0x000D
#define DEC_WORD  0x000E
#define NEG_BYTE  0x000F
#define NEG_WORD  0x0010
#define LOG_BYTE  0x0011
#define LOG_WORD  0x0012
#define MUL_BYTE  0x0013
#define MUL_WORD  0x0014
#define DIV_BYTE  0x0015
#define DIV_WORD  0x0016

#define CPU_HALT  0x0001

// define some enumerate constants
// to deal with flags register
enum {
	CF = 0,  PF = 2,  AF = 4,
	ZF = 6,	 SF = 7,  TF = 8,
	IF = 9,  DF = 10, OF = 11,
};

// define the index value of general register
enum {
	AX = 0,	CX = 1,	DX = 2,	BX = 3,
	SP = 4,	BP = 5,	SI = 6,	DI = 7,
};

// define the index value of general register
enum {
	AL = 0,	CL = 1,	DL = 2,	BL = 3,
	AH = 4,	CH = 5,	DH = 6,	BH = 7,
};
enum {
	DS = 0, CS = 1, SS = 2, ES = 3,
};

typedef struct {
	unsigned char  *ram;      // random access memory
	unsigned short flags;     // dedicated register
	unsigned short ip;        // dedicated register
	unsigned short regs[8];   // general registers
	unsigned short segs[6];   // segment registers
	unsigned short status;
} cpu_t;

typedef struct Instruction {
	unsigned short opcode; // instruction opcode
	unsigned short length; // instruction length
	unsigned long repeatable; // repeatable

	struct {
		char mod;          // operand addressing mode, including register operand
		char reg;          // general register number
		char rm;           // addressing mode
		char seg;          // segment register number
		long disp;         // displacement of immediate operand
		long imm;          // immediate value
		long address;      // The address offset after resolution
	} operand;

	void (*execute)(cpu_t *, struct Instruction *); // instruction interpreter
} instruction_t;

typedef struct {
	void (*executor)(cpu_t *, struct Instruction *);
	unsigned long action;
} decode_t;

// the interface to modify cpu's context
int  cpu_init(cpu_t *cpu);
int  cpu_get_reg(cpu_t *cpu, int index);
int  cpu_get_regb(cpu_t *cpu, int index);
int  cpu_get_seg(cpu_t *cpu, int index);
int  cpu_get_flag(cpu_t *cpu, int index);
int  cpu_pop_mem_word(cpu_t *cpu);
int  cpu_pop_mem_dword(cpu_t *cpu);
int  cpu_set_flag(cpu_t *cpu, int index, int value);
int  cpu_get_mem_byte(cpu_t *cpu, int seg, int offset);
int  cpu_get_mem_word(cpu_t *cpu, int seg, int offset);
int  cpu_get_mem_dword(cpu_t *cpu, int seg, int offset);
void cpu_loop(cpu_t *cpu);
void cpu_set_reg(cpu_t *cpu, int index, int value);
void cpu_set_regb(cpu_t *cpu, int index, int value);
void cpu_set_seg(cpu_t *cpu, int index, int value);
void cpu_push_mem_word(cpu_t *cpu, int value);
void cpu_push_mem_dword(cpu_t *cpu, int value);
void cpu_set_mem_byte(cpu_t *cpu, int seg, int offset, int value);
void cpu_set_mem_word(cpu_t *cpu, int seg, int offset, int value);
void cpu_set_mem_dword(cpu_t *cpu, int seg, int offset, int value);
void cpu_set_flags(cpu_t *cpu, int inst, int src, int dst, int ret);

#endif /* CPU_H */
